﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Data;
using System.Reflection;

namespace Untils
{
    public class DataConvertHelper
    {
        /// <summary>
        /// 对象转换实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="asObject"></param>
        /// <returns></returns>
        public static T ConvertObject<T>(object asObject)
        {
            //创建实体对象实例
            T t = Activator.CreateInstance<T>();
            if (asObject != null)
            {
                Type type = asObject.GetType();
                //遍历实体对象属性
                foreach (PropertyInfo info in typeof(T).GetProperties())
                {
                    object obj = null;
                    //取得object对象中此属性的值
                    object val = type.GetProperty(info.Name)?.GetValue(asObject);
                    if (val != null)
                    {
                        //非泛型
                        if (!info.PropertyType.IsGenericType)
                        {
                            obj = Convert.ChangeType(val, info.PropertyType);
                        }
                        else//泛型Nullable<>
                        {
                            Type genericTypeDefinition = info.PropertyType.GetGenericTypeDefinition();
                            if (genericTypeDefinition == typeof(Nullable<>))
                            {
                                obj = Convert.ChangeType(val, Nullable.GetUnderlyingType(info.PropertyType));
                            }
                            else
                            {
                                obj = Convert.ChangeType(val, info.PropertyType);
                            }
                        }
                        info.SetValue(t, obj, null);
                    }
                }
            }
            return t;
        }

        /// <summary>
        /// 泛型LIST转换DataTable
        /// </summary>
        public static DataTable ToDataTable<T>(List<T> items)
        {
            DataTable tb = new DataTable(typeof(T).Name);

            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (PropertyInfo prop in props)
            {
                Type t = GetCoreType(prop.PropertyType);
                tb.Columns.Add(prop.Name, t);
            }

            foreach (T item in items)
            {
                object[] values = new object[props.Length];

                for (int i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }

                tb.Rows.Add(values);
            }

            return tb;
        }

        /// <summary>
        /// DataTable转换ILIST
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="table">DataTable</param>
        /// <returns>返回ILIST类</returns>
        public static IList<T> ConvertTo<T>(DataTable table)
        {
            if (table == null)
            {
                return null;
            }

            List<DataRow> rows = new List<DataRow>();

            foreach (DataRow row in table.Rows)
            {
                rows.Add(row);
            }

            return ConvertTo<T>(rows);
        }

        /// <summary>
        /// IEnumerable接口类转换DataTable
        /// </summary>
        /// <typeparam name="T">泛型类</typeparam>
        /// <param name="collection">IEnumerable接口类</param>
        /// <returns>返回DataTable</returns>
        public static DataTable ToDataTable<T>(IEnumerable<T> collection)
        {
            PropertyInfo[] props = typeof(T).GetProperties();
            DataTable dt = new DataTable();
            dt.Columns.AddRange(props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray());
            if (collection.Count() > 0)
            {
                for (int i = 0; i < collection.Count(); i++)
                {
                    ArrayList tempList = new ArrayList();
                    foreach (PropertyInfo pi in props)
                    {
                        object obj = pi.GetValue(collection.ElementAt(i), null);
                        tempList.Add(obj);
                    }
                    object[] array = tempList.ToArray();
                    dt.LoadDataRow(array, true);
                }
            }
            return dt;
        }

        /// <summary>
        /// 判断类型是否可空类型
        /// </summary>
        public static bool IsNullable(Type t)
        {
            return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }

        /// <summary>
        /// 使用泛型，返回传入对象的属性，名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dx"></param>
        /// <returns></returns>
        public static List<string> GetAttr<T>(T t)
        {
            List<string> ls = new List<string>();
            Type types = t.GetType();
            foreach (PropertyInfo p in types.GetProperties())
            {
                //   p.PropertyType
                ls.Add(p.Name);
            }
            return ls;
        }

        /// <summary>
        /// 返回对象类型,如果可空类型返回正常非可空类型
        /// </summary>
        public static Type GetCoreType(Type t)
        {
            if (t != null && IsNullable(t))
            {
                if (!t.IsValueType)
                {
                    return t;
                }
                else
                {
                    return Nullable.GetUnderlyingType(t);
                }
            }
            else
            {
                return t;
            }
        }

        /// <summary>
        /// DataRow集合转换ILIST
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="rows">DataRow</param>
        /// <returns>返回ILIST类</returns>
        public static IList<T> ConvertTo<T>(IList<DataRow> rows)
        {
            IList<T> list = null;

            if (rows != null)
            {
                list = new List<T>();

                foreach (DataRow row in rows)
                {
                    T item = CreateItem<T>(row);
                    list.Add(item);
                }
            }

            return list;
        }

        /// <summary>
        /// 根据DataRow创建泛型类型数据
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="row">DataRow</param>
        /// <returns>泛型类型数据</returns>
        public static T CreateItem<T>(DataRow row)
        {
            T obj = default(T);
            if (row != null)
            {
                obj = Activator.CreateInstance<T>();

                foreach (DataColumn column in row.Table.Columns)
                {
                    PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName);
                    try
                    {
                        object value = row[column.ColumnName];
                        prop.SetValue(obj, value, null);
                    }
                    catch
                    {  //You can log something here
                       //throw;
                    }
                }
            }

            return obj;
        }

        public static JObject CopyJObject(JObject orgJObject)
        {
            JObject desJObject = new JObject();
            foreach (KeyValuePair<string, JToken> pro in orgJObject)
            {
                if (pro.Value == null)
                {
                    continue;
                }

                if (pro.Key.ToString() == "MsgContent")
                {
                    object v = JsonConvert.DeserializeObject(pro.Value.ToString());
                    JObject des = CopyJObject((JObject)v);
                    desJObject[pro.Key.Trim()] = des.ToString();
                    continue;
                }
                if (!string.IsNullOrEmpty(pro.Value.ToString()) && pro.Value.ToString() == ".")
                {
                    desJObject.Add(pro.Key, "0");
                    continue;
                }
                if (!string.IsNullOrEmpty(pro.Value.ToString()) && pro.Value.ToString()[..1] == ".")
                {
                    desJObject.Add(pro.Key, "0" + pro.Value);
                    continue;
                }
                if (pro.Value is JObject @object)
                {
                    JObject des = CopyJObject(@object);
                    desJObject[pro.Key.Trim()] = des;
                    continue;
                }
                if (pro.Value is JValue)
                {
                    if (string.IsNullOrEmpty((string)pro.Value))
                    {
                        continue;
                    }

                    if (pro.Value.ToString().Contains(" "))
                    {
                        string[] strs = pro.Value.ToString().Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        string finallStr = string.Join(" ", strs);
                        desJObject.Add(pro.Key, finallStr);
                    }
                    else
                    {
                        desJObject.Add(pro.Key, pro.Value);
                    }
                }
                if (pro.Value is JArray array1)
                {
                    JArray array = new JArray();
                    foreach (JToken item in array1)
                    {
                        if (item is JObject object1)
                        {
                            JObject des = CopyJObject(object1);
                            array.Add(des);
                        }
                        if (item is JValue)
                        {
                            array.Add(item.ToString().Trim());
                        }
                    }
                    if (array.Count != 0)
                    {
                        desJObject.Add(pro.Key.Trim(), array);
                    }
                }
            }
            return desJObject;
        }

        /// <summary>
        /// 字符串类型属性去空格
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T StringPropertyTrim<T>(T t)
        {
            IEnumerable<PropertyInfo> stringProperties = t.GetType().GetProperties().Where(p => p.PropertyType == typeof(string) && p.CanWrite);
            foreach (PropertyInfo stringProperty in stringProperties)
            {
                string currentValue = (string)stringProperty.GetValue(t, null);
                if (currentValue != null)
                {
                    stringProperty.SetValue(t, currentValue.Trim(), null);
                }
            }
            return t;
        }
    }
}
